查看原文
其他

前后端分离模式下的权限设计方案

作者 | _liuxx

来源 | cnblogs.com/liuyh/p/8027833.html

上一篇:两万字深度介绍分布式系统原理,一文入魂


前后端分离模式下,所有的交互场景都变成了数据,传统业务系统中的权限控制方案在前端已经不再适用,因此引发了我对权限的重新思考与设计。


权限控制到底控制的是什么?

在理解权限控制之前,需要明白两个概念:资源和权限。


什么是资源,对于一个系统来说,系统内部的所有信息都可以理解为这个系统的资源。


页面是资源、数据是资源、按钮是资源、图片是资源、甚至页面上一条分割线也可理解为是这个系统的资源。而权限就是访问某个资源所需要的标识。


无论系统的权限如何设计,在用户登录时,都可以计算得出用户所拥有的权限标识集合,也就确定了该用户能访问哪些系统资源,这就是我理解的权限控制的本质。


于是我们可以得出:权限控制是控制登录用户对于系统资源的访问

 

前后端分离模式下,前后端在权限控制中各自的职责是什么?


在弄清前后端在权限控制中各自的职责是什么之前,需要理解前后端各自在系统中的职责。这个还是很好理解:
  • 服务端:提供数据接口。

  • 前端:路由控制、页面渲染。


由于前端负责与用户交互,用户所能操作的资源入口都是由前端进行控制,那么前端的权限控制就包括:

  • 前端路由的权限控制,过滤非法请求,用户只能访问权限范围内的页面资源。

  • 页面内组件的权限控制,根据用户的权限控制页面组件的渲染。包括各种按钮、表格、分割线等。


随着前端组件化的快速发展,用户所看到的一切均可理解为组件,页面是个大组件,其内部由各个小组件拼凑而来,那么前端权限控制最终落地到对组件的权限控制。于是脑补了出了最优雅的权限组件使用方式:

<组件 permissionName='xxx' />

前端可以渲染出用户权限范围内的各种系统资源,但是不能保证数据接口的安全性,某些比较喜欢折腾的用户完全可以越过前端的页面访问我们系统的数据接口,那么服务端的权限控制最终落地到对接口的权限验证。


实现思路


引上文,系统的一切资源均可进行权限控制,实际上也可以做到,但在我们实际的操作过程中,往往不需要细化到分割线那种程度。这里以按钮级权限控制为例做实现说明,如果有更细粒度的权限需求,此思路依然可行。

关注顶级架构师公众号回复“架构整洁”,送你一份惊喜礼包。

  • 前端路由权限控制。用户登录时拿到用户拥有的权限标识集合,在前端存储。路由变化时,进行权限判断,通过则渲染对应页面组件,否则渲染403组件。示例代码:

let hasPermission = permission.check(current.permissionName);

<div className={styles.content}>
    {hasPermission ? children : <Exception type={403}/>}
</div>
  • 封装bird-button权限按钮组件,传入按钮所需权限名,内部进行权限判断,通过则渲染按钮。

<BirdButton permissionName={'sys'} type='primary'>测试按钮</BirdButton>
  • 服务端。服务端权限验证很好理解。使用拦截器验证当前请求的权限。代码示例:
public class SsoAuthorizeInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private TicketHandler ticketHandler;

    @Autowired
    private SsoAuthorizeManager authorizeManager;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod)) return false;

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        SsoAuthorize authorize = handlerMethod.getMethodAnnotation(SsoAuthorize.class);
        if (authorize != null) {
            TicketInfo ticketInfo = ticketHandler.getTicket(request);
            if (ticketInfo == null) {
                throw new UnAuthorizedException("用户信息已失效.");
            }

            String[] requirePermissions = authorize.permissions();
            if(requirePermissions.length==0)return true;

            boolean isCheckAll = authorize.isCheckAll();
            UserPermissionChecker permissionChecker = authorizeManager.getUserPermissionChecker();
            if(!permissionChecker.hasPermissions(ticketInfo.getUserId(),requirePermissions,isCheckAll)){
                throw new ForbiddenException("用户没有当前操作的权限.");
            }
        }

        return true;
    }
}


源码地址

本博客涉及到的前端权限控制思路均已在
github.com/liuxx001/bird-front

项目中实现,项目中除了按钮级权限方案还提供了后台业务系统开发中常用的数据组件,包括:

  • 下拉选择器:bird-selector
    github.com/liuxx001/bird-front/blob/master/doc/bird-selector.md
  • 全自动数据表格:bird-grid
    github.com/liuxx001/bird-front/blob/master/doc/bird-grid.md
  • 全自动树表:bird-tree-grid

    github.com/liuxx001/bird-front/blob/master/doc/bird-tree-grid.md
  • 数据树:bird-tree

    github.com/liuxx001/bird-front/blob/master/doc/bird-tree.md

  • 全自动表单:bird-form

    github.com/liuxx001/bird-front/blob/master/doc/bird-form.md

  • 权限按钮:bird-button

    github.com/liuxx001/bird-front/blob/master/doc/bird-button.md


所有业务组件的理念均是结合服务端接口进行组件的封装,兼顾灵活性的同时保证更优的业务开发速度。


公众号后台回复【架构】或者【架构整洁】有惊喜礼包!------END------

架构师交流群

 「顶级架构师」建立了读者架构师交流群,大家可以添加小编微信进行加群

扫描添加好友邀你进架构师群,加我时注明姓名+公司+职位】


版权申明:内容来源网络,版权归原作者所有。如有侵权烦请告知,我们会立即删除并表示歉意。谢谢。

猜你还想看

Springboot + Redis + 注解 + 拦截器来实现接口幂等性校验
Spring Boot+JWT+Shiro+MyBatisPlus 实现 RESTful 快速开发后端脚手架
搞懂这些SQL优化技巧,面试横着走
Spring Boot 中的 RestTemplate不好用?试试 Retrofit !

长按识别图片二维码关注,订阅更多精彩

顶级架构师,企业架构、系统架构、网站架构、大规模分布式架构、高可用架构等架构讨论,以及结合互联网技术的架构调整。欢迎有想法、乐于分享的架构师交流学习

: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存